#!/usr/bin/python
#
# Copyright 2010 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Base test class from which all tests inherit."""

# Python
import os
import sys
import unittest
import wsgiref.util

# Cruise Control for AppEngine
import app

# AppEngine
from google.appengine.ext import webapp
from google.appengine.api import apiproxy_stub_map  
from google.appengine.api import datastore_file_stub
from google.appengine.api import user_service_stub
from google.appengine.ext import webapp

APPLICATION_ID = 'test-id'

DEFAULT_REQUEST = {
    'SERVER_SOFTWARE': 'Development/1.0',
    'SCRIPT_NAME': '',
    'REQUEST_METHOD': 'GET',
    'PATH_INFO': '/',
    'QUERY_STRING': '',
    'CONTENT_LENGTH': '',
    'SERVER_PROTOCOL': 'HTTP/1.0',
    'HTTP_ACCEPT_CHARSET': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
    'HTTP_CONNECTION': 'keep-alive',
    'HTTP_CACHE_CONTROL': 'max-age=0',
    'HTTP_ACCEPT': """application/xml,application/xhtml+xml,text/html;
                      q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5""",
    'GATEWAY_INTERFACE': 'CGI/1.1',
    'HTTP_ACCEPT_LANGUAGE': 'en-US,en;q=0.8',
    'CONTENT_TYPE': 'application/x-www-form-urlencoded',
    'HTTP_HOST': 'localhost:8080',
    'SERVER_NAME': 'localhost',
    'REMOTE_ADDR': '127.0.0.1',
    'SERVER_PORT': '8080',
    'AUTH_DOMAIN': 'gmail.com',
    'USER_IS_ADMIN': '1',
    'USER_EMAIL': 'test@example.com',
    'USER_ID': '1',
    'APPLICATION_ID': APPLICATION_ID,
}

class MockStartResponse(object):
    """Mock wsgi start_response."""
    
    def __init__(self):
        self.status = None
        self.headers = {}
        self.response_body = ''

    def _update_status(self, status):
        """Sets the status to the current HTTP response code.
        
        Args:
            status: a string containing the response code and a message (e.g., 
                "200 OK")
        """
        self.status = int(status.split()[0])

    def _update_headers(self, headers):
        """Sets the headers to the current HTTP response headers.
        
        Args:
            headers: a list of tuples with (key, value) pairs.
        """
        request_headers = {}
        for name, val in headers:
            request_headers[name] = val
        self.headers.update(request_headers)
        
    def start_response(self, status, headers, exec_info=None):
        """Mock wsgi start_response.
        
        Waits for a response from webapp and updates the status and headers
        accordingly.
        
        Args:
            status: a string containing the response code and a message (e.g., 
                "200 OK")
            headers: a list of tuples with (key, value) pairs.
            exec_info: this is not used.
        Returns:
            reference to update_response_body function. This is meant to mock
            dev_appserver's return of sys.stdout.write
        """
        self._update_status(status)
        self._update_headers(headers)
        return self.update_response_body
        
    def update_response_body(self, body):
        """Saves the webapp's HTML response."""
        self.response_body = body


class CruiseControlTest(unittest.TestCase):
    """Cruise Control for AppEngine's base test class.
    
    All tests should inherit this class.
    """

    def setUp(self):
        """Setup for Cruise Control for AppEngine's base test.
        
        Create our datastore and user proxy stubs. Add more stubs here as
        needed (i.e., mail, url fetch, etc...).
        
        All tests should inherit this test.
        """
        apiproxy_stub_map.apiproxy = apiproxy_stub_map.APIProxyStubMap() 
        datastore_stub = datastore_file_stub.DatastoreFileStub(
            APPLICATION_ID, None)  
        apiproxy_stub_map.apiproxy.RegisterStub('datastore', datastore_stub)
        user_stub = user_service_stub.UserServiceStub()
        apiproxy_stub_map.apiproxy.RegisterStub('user', user_stub)
        
        # Update os.envrion with our default webapp request info.
        os.environ.update(DEFAULT_REQUEST)
        
        self.mock_start_response = MockStartResponse()
        self.app = webapp.WSGIApplication(app.HANDLERS)
        
        self.set_up()

    def set_up(self):
        """This is meant to be overridden by a subclass."""
        pass

    def tearDown(self):
        """Resets the testing environment."""
        self.tear_down()
        
    def tear_down(self):
        """This is meant to be overridden by a subclass."""
        pass

    def wsgi_request(self, custom_params={}):
        """Sets default wsgi request params and optionally custom params.
        
        Args:
            custom_params: dictionary containing the params that should be
                updated.
        Returns:
            req: a dictionary containing the wsgi request params.
        """
        req = dict(os.environ)
        wsgi = {
            'wsgi.input': sys.stdin,
            'wsgi.errors': sys.stderr,
            'wsgi.version': (1, 0),
            'wsgi.run_once': True,
            'wsgi.url_scheme': wsgiref.util.guess_scheme(req),
            'wsgi.multithread': False,
            'wsgi.multiprocess': False
        }
        req.update(wsgi)
        if custom_params:
            req.update(custom_params)
        return req